﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;
using AdminModule.IndexMarkServiceReference;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.ComponentModel;
using SharedCode;
using AdminModule.CommonClasses;
using AdminModule.CustomXAMLElements;
using AdminModule.UserControls.Common;
using AdminModule.Filter;
using AdminModule.AnswerLog;
using AdminModule.AnswerLog.DataSource;

namespace AdminModule.Views
{
    public enum LogName { Answer, Input };

    public partial class ViewAnswerLog : Page
    {
        private IndexMarkServiceClient client = new IndexMarkServiceClient();

        private LogName logName;

        #region Делегаты
        public delegate void GetLogDelegate(DateTime from, DateTime to);
        public delegate void GetLogTopDelegate();
        public delegate void SaveLogDelegate(ObservableCollection<DTOBase> list);
        public delegate void ClearLogDelegate();
        protected delegate void GroupingDelegate();

        public GetLogDelegate GetLog;
        public GetLogTopDelegate GetLogTop;
        public SaveLogDelegate SaveLog;
        public ClearLogDelegate ClearLog;
        #endregion

        #region Коллекции
        private List<CheckBox> CheckBoxes = new List<CheckBox>();
        private ObservableCollection<DTOBase> SelectedItems = new ObservableCollection<DTOBase>();

        private System.Collections.IEnumerable ItemsSource
        {
            get
            {
                return this.pagedCollectionView.SourceCollection;
            }
            set
            {
                ObservableCollection<GroupDescription> tmp = pagedCollectionView.GroupDescriptions;
                pagedCollectionView = null;

                //switch(logName)
                //{
                //    case LogName.Answer:
                //        pagedCollectionView = new PagedCollectionView(new GridTreeDataSource(value, item => (item as AdmAnswerLog).Childs).Source); 
                //    break;

                //    case LogName.Input:
                //        pagedCollectionView = new PagedCollectionView(value);
                //    break;
                //}
                pagedCollectionView = new PagedCollectionView(value);

                foreach (GroupDescription gd in tmp) pagedCollectionView.GroupDescriptions.Add(gd);
                dataGrid.ItemsSource = pagedCollectionView;
            }
        }
        #endregion

        private const string gByDepartmentName = "Отдел";
        private const string gByCharacteristicName = "Показатель";
        private const string gByPersonName = "Сотрудник";
        private const string gByUserName = "Пользователь";

        private PagedCollectionView pagedCollectionView = new PagedCollectionView(new List<object>());
        private readonly PropertyGroupDescription gByDepartment = new PropertyGroupDescription(gByDepartmentName);
        private readonly PropertyGroupDescription gByCharacteristic = new PropertyGroupDescription(gByCharacteristicName);
        private readonly PropertyGroupDescription gByPerson = new PropertyGroupDescription(gByPersonName);
        private readonly PropertyGroupDescription gByUser = new PropertyGroupDescription(gByUserName);

        public ViewAnswerLog(LogName logName)
        {
            InitializeComponent();

            this.logName = logName;
            SelectedItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(SelectedItems_CollectionChanged);
            logFilter.Added += new LogFilter.AddedHandler(logFilter_Changed);
            logFilter.Deleted += new LogFilter.DeletedHandler(logFilter_Changed);

            #region Подписка на события
            // AnswerLog
            client.GetAnswerLogTopCompleted += (s, ev) =>
            {
                this.ItemsSource = ev.Result;
                try
                {
                    fromDate.SelectedDate = (from e in ev.Result.Cast<AdmAnswerLog>() select e.CurrentTime).Min();
                    toDate.SelectedDate = (from e in ev.Result.Cast<AdmAnswerLog>() select e.CurrentTime).Max();
                }
                catch (InvalidOperationException) { }
                VisibleControls(true);
            };

            client.GetAnswerLogCompleted += (s, ev) =>
            {
                this.ItemsSource = ev.Result;
                VisibleControls(true);
            };

            client.SaveAnswerLogCompleted += (s, ev) =>
            {
                ShowSaveRelust(ev);
                filterButton_Click(null, null);
            };
            // ---

            // InputLog
            client.GetInputLogTopCompleted += (s, ev) =>
            {
                this.ItemsSource = ev.Result;
                try
                {
                    fromDate.SelectedDate = (from e in ev.Result.Cast<AdmInputLog>() select e.Date).Min();
                    toDate.SelectedDate = (from e in ev.Result.Cast<AdmInputLog>() select e.Date).Max();
                }
                catch (InvalidOperationException) { }
                VisibleControls(true);
            };

            client.GetInputLogCompleted += (s, ev) =>
            {
                this.ItemsSource = ev.Result;
                VisibleControls(true);
            };

            client.SaveInputLogCompleted += (s, ev) =>
            {
                ShowSaveRelust(ev);
                filterButton_Click(null, null);
            };
            // ---
            #endregion

            #region Установка параметров журнала
            switch (logName)
            {
                case LogName.Answer:
                    this.GetLog = this.GetAnswerLogAsync;
                    this.GetLogTop = client.GetAnswerLogTopAsync;
                    this.SaveLog = client.SaveAnswerLogAsync;
                    this.ClearLog = client.ClearAnswerLogAsync;
                    this.answerGrouping.Visibility = System.Windows.Visibility.Visible;
                    SetTemplate("AnswerLog");

                    logFilter.InitFilter(new List<FilterAttribute<FilterAnswerLogAttributes>>
                    {
                        new FilterAttribute<FilterAnswerLogAttributes>
                        {
                            Attribute = FilterAnswerLogAttributes.Volume,
                            AttributeName = "Значение показателя",
                            IsString = false
                        },
                        new FilterAttribute<FilterAnswerLogAttributes>
                        {
                            Attribute = FilterAnswerLogAttributes.User,
                            AttributeName = "Пользователь",
                            IsString = true
                        },
                        new FilterAttribute<FilterAnswerLogAttributes>
                        {
                            Attribute = FilterAnswerLogAttributes.Person,
                            AttributeName = "Сотрудник",
                            IsString = true
                        },
                        new FilterAttribute<FilterAnswerLogAttributes>
                        {
                            Attribute = FilterAnswerLogAttributes.CharacteristicName,
                            AttributeName = "Показатель",
                            IsString = true
                        },
                        new FilterAttribute<FilterAnswerLogAttributes>
                        {
                            Attribute = FilterAnswerLogAttributes.Department,
                            AttributeName = "Отдел",
                            IsString = true
                        },
                        new FilterAttribute<FilterAnswerLogAttributes>
                        {
                            Attribute = FilterAnswerLogAttributes.Operation,
                            AttributeName = "Операция",
                            IsString = true,
                            AllowedValues = new List<FilterAllowedValues>
                            {
                                new FilterAllowedValues("Добавлено", StateObject.Created),
                                new FilterAllowedValues("Изменено", StateObject.Updated),
                                new FilterAllowedValues("Удалено", StateObject.Deleted)
                            }
                        }
                    });
                    break;

                case LogName.Input:
                    this.GetLog = this.GetInputLogAsync;
                    this.GetLogTop = client.GetInputLogTopAsync;
                    this.SaveLog = client.SaveInputLogAsync;
                    this.ClearLog = client.ClearInputLogAsync;
                    this.inputGrouping.Visibility = System.Windows.Visibility.Visible;
                    SetTemplate("InputLog");

                    logFilter.InitFilter(new List<FilterAttribute<FilterInputLogAttributes>>
                    {
                        new FilterAttribute<FilterInputLogAttributes>
                        {
                            Attribute = FilterInputLogAttributes.User,
                            AttributeName = "Пользователь",
                            IsString = true
                        }
                    });
                    break;
            }
            #endregion
        }

        void logFilter_Changed(int count, int rowHeight)
        {
            //if (count * rowHeight <= logFilter.GetMinHeight)
            //    dataGrid.Margin = new Thickness(0, rowHeight, 0, 0);
            //else
            //    dataGrid.Margin = new Thickness(0, count * rowHeight, 0, 0);
        }

        void SelectedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            deleteButton.IsEnabled = SelectedItems.Count > 0;
        }

        private void GetAnswerLogAsync(DateTime from, DateTime to)
        {
            client.GetAnswerLogAsync(from, to, this.logFilter.GetFilters(), false);
        }

        private void GetInputLogAsync(DateTime from, DateTime to)
        {
            client.GetInputLogAsync(from, to, this.logFilter.GetFilters());
        }

        private void ShowSaveRelust(AsyncCompletedEventArgs ev)
        {
            if (ev.Error != null)
            {
                ErrorWindow.Show(ev.Error);
                return;
            }
        }

        private void SetTemplate(string name)
        {
            ColumnCollection col = this.Resources[name] as ColumnCollection;
            this.dataGrid.Columns.Clear();
            foreach (var column in col)
            {
                this.dataGrid.Columns.Add(column);
            }
        }

        private void deleteButton_Click(object sender, RoutedEventArgs e)
        {
            if (SelectedItems.Count == 0 && dataGrid.SelectedItem == null)
            {
                MessageBox.Show("Отметьте записи, которые необходимо удалить", MyAssemblyInfo.Title, MessageBoxButton.OK);
                return;
            }
            MessageBoxResult r = MessageBox.Show("Удалить?", MyAssemblyInfo.Title, MessageBoxButton.OKCancel);
            if (r == MessageBoxResult.Cancel) return;
            VisibleControls(false);

            if (SelectedItems.Count == 0)
            {
                (dataGrid.SelectedItem as DTOBase).State = StateObject.Deleted;
                this.SaveLog(new ObservableCollection<DTOBase> { dataGrid.SelectedItem as DTOBase });
            }
            else
            {
                foreach (var el in SelectedItems)
                {
                    el.State = StateObject.Deleted;
                }
                this.SaveLog(this.SelectedItems);
            }
        }

        private void filterButton_Click(object sender, RoutedEventArgs e)
        {
            if (fromDate.SelectedDate.Value.Date > toDate.SelectedDate.Value.Date)
            {
                MessageBox.Show("Дата \"От\" должна быть меньше или равна дате \"До\"", MyAssemblyInfo.Title, MessageBoxButton.OK);
                return;
            }
            VisibleControls(false);
            // Очищаем DataGrid
            this.ItemsSource = new ObservableCollection<DTOBase>();
            this.GetLog((DateTime)fromDate.SelectedDate, (DateTime)toDate.SelectedDate);
        }

        private void DatePicker_Loaded(object sender, RoutedEventArgs e)
        {
            fromDate.SelectedDate = DateTime.Now;
            toDate.SelectedDate = DateTime.Now;
        }

        private void VisibleControls(bool isVisibility)
        {
            progressBar.IsVisibility = (isVisibility == true) ? Visibility.Collapsed : Visibility.Visible;
            buttonsPanel.Visibility = (isVisibility == true) ? Visibility.Visible : Visibility.Collapsed;
        }

        private void CheckBox_Loaded(object sender, RoutedEventArgs e)
        {
            this.CheckBoxes.Add(sender as CheckBox);
        }

        /// <summary>
        /// Отметить запись
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CheckBox_Checked(object sender, RoutedEventArgs e)
        {
            CheckBox checkBox = sender as CheckBox;
            DTOBase item = null;

            if (logName == LogName.Answer)
            {
                if (checkBox.Tag is GridTreeDataItem)
                {
                    GridTreeDataItem dataItem = checkBox.Tag as GridTreeDataItem;
                    item = dataItem.Item as DTOBase;
                }
                else
                {
                    item = checkBox.Tag as DTOBase;
                }
            }
            else
            {
                item = checkBox.Tag as DTOBase;
            }

            if (checkBox.IsChecked == true)
            {
                if (!this.SelectedItems.Contains(item))
                {
                    this.SelectedItems.Add(item);
                }
            }
            else
            {
                this.SelectedItems.Remove(item);
            }
        }

        /// <summary>
        /// Отметить всё
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void commonCheckBox_Checked(object sender, RoutedEventArgs e)
        {
            CheckBox checkBox = sender as CheckBox;
            foreach (var cb in this.CheckBoxes)
            {
                if (checkBox.IsChecked == true)
                    cb.IsChecked = true;
                else
                    cb.IsChecked = false;
            }
        }

        private void ChangeGrouping(bool add, PropertyGroupDescription description, string column)
        {
            if (add == true)
                pagedCollectionView.GroupDescriptions.Add(description);
            else
                pagedCollectionView.GroupDescriptions.Remove(description);

            switch (column)
            {
                case gByUserName:
                    dataGrid.Columns[1].Visibility = (add == true) ? Visibility.Collapsed : Visibility.Visible;
                    break;

                case gByDepartmentName:
                    dataGrid.Columns[7].Visibility = (add == true) ? Visibility.Collapsed : Visibility.Visible;
                    break;

                case gByCharacteristicName:
                    dataGrid.Columns[4].Visibility = (add == true) ? Visibility.Collapsed : Visibility.Visible;
                    dataGrid.Columns[5].Visibility = (add == true) ? Visibility.Visible : Visibility.Collapsed;
                    break;

                case gByPersonName:
                    dataGrid.Columns[6].Visibility = (add == true) ? Visibility.Collapsed : Visibility.Visible;
                    break;
            }
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            VisibleControls(false);
            this.GetLogTop();
        }

        private void clearButton_Click(object sender, RoutedEventArgs e)
        {
            MessageBoxResult r = MessageBox.Show("Очистить журнал?", MyAssemblyInfo.Title, MessageBoxButton.OKCancel);
            if (r == MessageBoxResult.Cancel) return;
        }

        private void groupByDepartment_Checked(object sender, RoutedEventArgs e)
        {
            CheckBox cb = sender as CheckBox;
            ChangeGrouping((cb.IsChecked ?? false), gByDepartment, gByDepartmentName);
        }

        private void groupByCharacterisitc_Checked(object sender, RoutedEventArgs e)
        {
            CheckBox cb = sender as CheckBox;
            ChangeGrouping((cb.IsChecked ?? false), gByCharacteristic, gByCharacteristicName);
        }

        private void groupByPerson_Checked(object sender, RoutedEventArgs e)
        {
            CheckBox cb = sender as CheckBox;
            ChangeGrouping((cb.IsChecked ?? false), gByPerson, gByPersonName);
        }

        private void groupByUser_Checked(object sender, RoutedEventArgs e)
        {
            CheckBox cb = sender as CheckBox;
            ChangeGrouping((cb.IsChecked ?? false), gByUser, gByUserName);
        }

        private void historyButton_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            AdmAnswerLog answer = button.Tag as AdmAnswerLog;

            ViewAnswerLogDetails details = new ViewAnswerLogDetails(answer.IDAnswer);
            details.Closed += (object s, EventArgs ev) =>
                {
                    if(details.AnswerLogChanged) filterButton_Click(sender, e);
                };
            details.Show();
        }
    }
}
